package primetest.impl.dao;

import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;


import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import primetest.dto.PatientDto;
import primetest.impl.dao.PatientDao;
import primetest.impl.dao.Transaction;

public class PatientDao implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = 3338343398228607250L;

	private final Logger logger = LoggerFactory.getLogger(this.getClass());



	private static List<PatientDto> allItems = null;
	private static HashMap<Integer, PatientDto> map = null;
	private static AtomicInteger count = null;

	@Inject
	public PatientDao(){
	}


	public List<PatientDto> getPatientList(Transaction transaction) throws IOException {
		if (allItems != null) {
			return allItems;
		}
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;
		map = new HashMap<Integer, PatientDto>();
		int cnt = 0;
		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(GET_ALL);
			resultSet = prepareStatement.executeQuery();
			while (resultSet.next()) {
				PatientDto patientDto = makePatientDto(transaction, resultSet);
				map.put(patientDto.getSeq(), patientDto);
				if (patientDto.getSeq() > cnt) {
					cnt = patientDto.getSeq();
				}
			}
			allItems = new ArrayList<PatientDto>(map.values());
			count = new AtomicInteger(++cnt);
			return allItems;
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}

	private PatientDto makePatientDto(Transaction transaction, ResultSet resultSet) throws SQLException, IOException {
		PatientDto PatientDto = new PatientDto(resultSet.getInt(1), resultSet.getString(2),
				resultSet.getInt(3), resultSet.getDate(4), resultSet.getString(5));
		return PatientDto;
	}



	public PatientDto getPatient(Transaction transaction, int patientSeq) throws IOException {
		if(allItems == null){
			getPatientList(transaction);
		}
		return map.get(patientSeq);
	}


	public void addPatient(Transaction transaction, PatientDto patientDto) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;


		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(INSERT_ONE);
			patientDto.setSeq(count.getAndIncrement());
			prepareStatement.setInt(1, patientDto.getSeq());
			prepareStatement.setString(2, patientDto.getName());
			prepareStatement.setInt(3, patientDto.getGender());
			prepareStatement.setDate(4, new Date(patientDto.getBirthDate().getTime()));
			prepareStatement.setString(5, patientDto.getPhoneNumber());
			prepareStatement.executeUpdate();
			map.put(patientDto.getSeq(), patientDto);
			allItems.add(patientDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}
	}


	public void updatePatient(Transaction transaction, PatientDto patientDto) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;


		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(UPDATE_ONE);
			prepareStatement.setInt(5, patientDto.getSeq());
			prepareStatement.setString(1, patientDto.getName());
			prepareStatement.setInt(2, patientDto.getGender());
			prepareStatement.setDate(3, new Date(patientDto.getBirthDate().getTime()));
			prepareStatement.setString(4, patientDto.getPhoneNumber());
			prepareStatement.executeUpdate();
			logger.debug("update the patient info in db" + " seq: " + patientDto.getSeq() + " gender: " + patientDto.getGender());
			map.put(patientDto.getSeq(), patientDto);
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}


	public void deletePatient(Transaction transaction, int patientSeq) throws IOException {
		PreparedStatement prepareStatement = null;
		ResultSet resultSet = null;


		try {
			Connection connection = transaction.getResource(Connection.class);
			prepareStatement = connection.prepareStatement(DELETE_ONE);
			prepareStatement.setInt(1, patientSeq);
			prepareStatement.executeUpdate();
			allItems.remove(map.remove(patientSeq));
		} catch (SQLException e) {
			throw new IOException(e);
		} finally {
			if (resultSet != null) {
				try {
					resultSet.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}

			if (prepareStatement != null) {
				try {
					prepareStatement.close();
				} catch (SQLException e) {
					logger.warn(e.getMessage(), e);
				}
			}
		}

	}

	private static final String GET_ALL = "select seq, name, gender, birth_date, phone_number from s_patient order by seq";
	private static final String INSERT_ONE = "insert into s_patient(seq, name, gender, birth_date, phone_number) values (?, ?, ?, ?, ?)";
	private static final String UPDATE_ONE = "update s_patient set name = ?, gender = ?, birth_date = ?, phone_number = ? where seq = ?";
	private static final String DELETE_ONE = "delete from s_patient where seq = ?";

}
